package rdbms;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Set;

import rdbms.ddl.Field;
import rdbms.ddl.Table;
import valuetypes.DBValue;
import valuetypes.GroupValue;
import valuetypes.NumericValue;
import exception.EntryException;
import exception.InvalidFieldException;


public class Entry {
	private static final String FIELD_ID = "_id";
	protected Table parentTable;
	protected LinkedHashMap<Field, DBValue> fieldValues;
	protected int ID;
	
	public Entry(Table table){
//		fieldValues = new ArrayList<>(parent.getFieldCount());
		fieldValues = new LinkedHashMap<>();
		
		parentTable = table;
		ArrayList<Field> fields = new ArrayList<Field>(table.getFields().values());
//		for(int i = 0; i < table.getFieldCount(); i++){
//			fieldValues.put(new NullValue());
//		}
		for(Field f : fields){
			try {
				fieldValues.put(f, f.getFieldType().getBaseClass().newInstance());
			} catch (InstantiationException | IllegalAccessException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}	

	public void setValue(String fieldName, DBValue value) throws InvalidFieldException, EntryException  {
//		if(fieldName.equals(FIELD_ID)){
//			throw EntryException.readOnly(fieldName);
//		}		
		Field f = parentTable.getField(fieldName);
		if(f.isValidValue(value, parentTable)){
			fieldValues.put(f, value);
		}
		else{
			throw EntryException.badEntry(fieldName, value);
		}
	}
	
	@Override
	public String toString() {
		String s = ID + "\t|";
		Collection<DBValue> values = fieldValues.values();
		for(DBValue v: values){
			if(v != null){
				s += "|" + v.toString();
			}
			else {
				s += "|" + "NULL";
			}
		}
		return s;
	}

	public DBValue getValue(Field field) {
		return fieldValues.get(field);
	}

	public void setID(int id) {
		this.ID = id;
		try {
			fieldValues.put(parentTable.getField(FIELD_ID), new NumericValue(id));
		} catch (InvalidFieldException e) {
			//Should never go wrong
			e.printStackTrace();
		}
	}
	
	public int getID(){
		return ID;
	}

	public boolean validate() {
		Set<Field> fields = fieldValues.keySet();
		for(Field f : fields){
			if(!f.getName().equals(FIELD_ID) && !f.isValidValue(fieldValues.get(f), parentTable)){
				return false;
			}
		}
		return true;
	}

	public GroupValue getGroupValue(Group group) {
		return new GroupValue(group, this);
	}

	public byte[] serialize() {
		ArrayList<Byte> bytes = new ArrayList<>();
		byte[] id = new NumericValue(ID).getData();
		for(byte b : id)bytes.add(b);
		byte[] dbId = parentTable.getDatabase().getId().getData();
		for(byte b : dbId)bytes.add(b);
		byte[] tableId = parentTable.getId().getData();
		for(byte b : tableId)bytes.add(b);
		
		
		Collection<DBValue> vals = fieldValues.values();
		for(DBValue v : vals){
			byte[] data = v.getData();
			for(byte b : data)bytes.add(b);
		}
		byte[] out = new byte[bytes.size()];
		for(int i = 0; i < bytes.size(); i++){
			out[i] = bytes.get(i);
		}
		return out;
	}

	public boolean isReferredBy(Group g) {
		GroupValue gv = getGroupValue(g);
		for(Group referer: g.getReferrals()){
			if(referer.refersTo(gv)){
				return true;
			}
		}
		return false;
	}
	
	
	
}
